package com.hzy.uninstall;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;

import android.content.Context;
import android.os.Build;
import android.os.Environment;

public class UninstallCallback {

	private int mPid = 0;
	private static UninstallCallback mInstance = null;
	private boolean mIsRunning = false;
	private Context mContext;

	private String mFileDir;
	private String mAppDir;
	private String mObservedFile;
	private String mLockFile;
	private String mLocalPage;
	private String mLocalUrl;
	private String mRemoteUrl;
	private String mUserSerial;

	/** private constructor */
	private UninstallCallback(Context c) {
		/** API level大于17，需要获取userSerialNumber */
		if (Build.VERSION.SDK_INT >= 17) {
			mUserSerial = getUserSerial(c);
		}
		this.mContext = c;
		mFileDir = c.getFilesDir().getPath();
		mAppDir = c.getFilesDir().getParent();
		mObservedFile = mFileDir + File.separator + UninstallConsts.OBSERVED_FILE;
		mLockFile = mFileDir + File.separator + UninstallConsts.LOCK_FILE;
		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
			String exPath = Environment.getExternalStorageDirectory().getAbsolutePath();
			mLocalPage = exPath + File.separator + UninstallConsts.EXTERNAL_APP_PATH + File.separator + UninstallConsts.LOCAL_PAGE_NAME;
		}
		if (mLocalPage != null) {
			File localPageFile = new File(mLocalPage);
			if (!localPageFile.exists()) {
				prepareLocalPage();
			}
			mLocalUrl = UninstallConsts.LOCAL_FILE_URL_HEADER + mLocalPage;
		}
		mRemoteUrl = UninstallConsts.REMOTE_URL;
	};

	/**
	 * copy local page from assets
	 */
	private void prepareLocalPage() {
		try {
			InputStream ins = mContext.getAssets().open(UninstallConsts.LOCAL_PAGE_NAME);
			File ouf = new File(mLocalPage);
			File parent = ouf.getParentFile();
			if (!parent.exists()) {
				parent.mkdirs();
			}
			OutputStream ous = new FileOutputStream(ouf);
			byte[] buffer = new byte[1024 * 1024];
			int count = 0;
			while ((count = ins.read(buffer)) > 0) {
				ous.write(buffer, 0, count);
			}
			ous.close();
			ins.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/** 获取单例模式实例 */
	public static UninstallCallback getInstance(Context c) {
		if (mInstance == null) {
			synchronized (UninstallCallback.class) {
				if (mInstance == null) {
					mInstance = new UninstallCallback(c);
				}
			}
		}
		return mInstance;
	}

	/**
	 * start to listen
	 * 
	 * @param isLocalPage
	 *            launch local page if true, otherwise remote url
	 */
	public void start(boolean isLocalPage) {
		if(isRunning()){
			stop();
		}
		if (isLocalPage) {
			mPid = init(mAppDir, mFileDir, mObservedFile, mLockFile, mLocalPage, mRemoteUrl, mLocalUrl, mUserSerial);
		} else {
			mPid = init(mAppDir, mFileDir, mObservedFile, mLockFile, null, mRemoteUrl, mLocalUrl, mUserSerial);
		}
		if (mPid > 0) {
			mIsRunning = true;
		}
	}

	/** 结束卸载监听 */
	public void stop() {
		if (mPid > 0) {
			android.os.Process.killProcess(mPid);
			mPid = 0;
		}
		mIsRunning = false;
	}

	public boolean isRunning() {
		return mIsRunning;
	}

	/** 由于targetSdkVersion低于17，只能通过反射获取 */
	private String getUserSerial(Context c) {
		Object userManager = c.getSystemService("user");
		if (userManager == null) {
			return null;
		}
		try {
			Method myUserHandleMethod = android.os.Process.class.getMethod("myUserHandle", (Class<?>[]) null);
			Object myUserHandle = myUserHandleMethod.invoke(android.os.Process.class, (Object[]) null);
			Method getSerialNumberForUser = userManager.getClass().getMethod("getSerialNumberForUser", myUserHandle.getClass());
			long userSerial = (Long) getSerialNumberForUser.invoke(userManager, myUserHandle);
			return String.valueOf(userSerial);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	static {
		System.loadLibrary("uninstall");
	}

	/**
	 * init the file listen process
	 * 
	 * @param appDir
	 * @param appFileDir
	 * @param appObservedFile
	 * @param lockFile
	 * @param localHtml
	 * @param remoteUrl
	 * @param localUrl
	 * @param userSerial
	 * @return
	 */
	private static native int init(String appDir, String appFileDir, String appObservedFile, String lockFile, String localHtml, String remoteUrl, String localUrl, String userSerial);
	
}
